#include "serial_port.hpp"

#define BUFFER_SIZE 1024
#define MAX_QUEUE_SIZE 10       // 最大队列长度

namespace gimabl {

    SerialPort::SerialPort(const std::string& port_name, int32_t baud_rate,DataBits bits, Parity parity, 
            StopBits stop_bits, FlowControl flow_control)
    :m_fd(-1),
    m_portName(port_name), 
    m_baudRate(baud_rate),
    m_bits(bits), 
    m_parity(parity), 
    m_stopBits(stop_bits),
    m_flowControl(flow_control),
    m_connected(false),
    m_stopped(false),
    m_serialRecHandle(nullptr),
    m_timeoutMs(0),
    m_WtimeOutMs(0),
    m_startWriteThread(false)
    {
        
    }

    SerialPort::~SerialPort()
    {
        if (m_fd != -1)
        {
            close(m_fd);
        }
    }

    int32_t SerialPort::openSerial() 
    {
        int32_t ret=-1;
        
        if(m_portName.empty())
        {
            std::cerr << "Serial port name is empty" << std::endl;
            return ret;
        }

        m_fd= open(m_portName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
        if (m_fd < 0) {
            perror("open_serial failed");
            return ret;
        }

        struct termios tty;
        memset(&tty, 0, sizeof(tty));
        if (tcgetattr(m_fd, &tty) != 0)
        {
            perror("tcgetattr");
            return ret;
        }

        speed_t stSpeed;
        switch (m_baudRate)
        {
        case 9600:
            stSpeed = B9600;
            break;
        case 38400:
            stSpeed = B38400;
            break;
        case 115200:
            stSpeed = B115200;
            break;
        case 230400:
            stSpeed = B230400;
            break;
        case 921600:
            stSpeed = B921600;
            break;
        case 1000000:
            stSpeed = B1000000;
            break;
        default:
            fprintf(stderr, "Unsupported baud rate\n");
            return ret;

        }

        cfsetispeed(&tty, stSpeed);
        cfsetospeed(&tty, stSpeed);

        // 数据位
        tty.c_cflag &= ~CSIZE;
        switch (m_bits) {
            case DataBits::Five: tty.c_cflag |= CS5; break;
            case DataBits::Six :tty.c_cflag |= CS6; break;
            case DataBits::Seven: tty.c_cflag |= CS7; break;
            case DataBits::Eight:
            default: tty.c_cflag |= CS8; break;
        }

        // 停止位
        if (m_stopBits == StopBits::Two)
            tty.c_cflag |= CSTOPB;
        else
            tty.c_cflag &= ~CSTOPB;

        // 校验位
        if (m_parity == Parity::None) {
            tty.c_cflag &= ~PARENB;
        } else {
            tty.c_cflag |= PARENB;
            if (m_parity == Parity::Odd)
                tty.c_cflag |= PARODD;
            else
                tty.c_cflag &= ~PARODD;
        }

        tty.c_iflag &= ~(IXON | IXOFF | IXANY);   // 禁用软件流控
        tty.c_cflag |= (CLOCAL | CREAD);          // 启动接收器
        tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入模式
        tty.c_oflag &= ~OPOST;

        tcflush(m_fd, TCIFLUSH);  // 清空接收缓冲区
        if (tcsetattr(m_fd, TCSANOW, &tty) != 0)
        {
            perror("tcsetattr");
            return ret;
        }
        m_connected= true;
        return m_fd;
    }

    void SerialPort::closeSerial()
    {
        m_stopped =true;
        m_connected= false;
        if (m_fd >=0)
        {
            close(m_fd);
            m_fd =-1;
        }
        if(m_recvThread.joinable())
        {
            m_recvThread.join();
        }

        if(m_startWriteThread)
        {
            m_writeCv.notify_one();
            if(m_writeThread.joinable())
            {
                m_writeThread.join();
            }
            m_startWriteThread= false;
            while (!m_writeQueue.empty()) {
                m_writeQueue.pop(); // 逐个弹出，触发字符串析构
            }
        }
    }

    bool SerialPort::isStopped() const
    {
        return m_stopped;
    }

    void SerialPort::startReceiving(serialRecHandle serialRecHandle,int32_t timeout_ms) 
    {
        if(!m_connected )
        {
            std::cerr << "Serial port is not connected" << std::endl;
            return;
        }
        if(!serialRecHandle)
        {
            std::cerr << "Serial port receive handle is null" << std::endl;
            return;
        }
        if(timeout_ms <= 0)
        {
            std::cerr << "Serial port timeout is invalid" << std::endl;
            return;
        }
        m_timeoutMs= timeout_ms;
        m_serialRecHandle= serialRecHandle;
        m_recvThread = std::thread(&SerialPort::receiveLoop, this);
    }

    void SerialPort::receiveLoop()
    {
        uint8_t buffer[BUFFER_SIZE];
        int32_t max_fd = m_fd; // 最大文件描述符
        fd_set readfds;

        while (!m_stopped)
        {
            FD_ZERO(&readfds);
            FD_SET(m_fd, &readfds);

            struct timeval timeout;
            timeout.tv_sec = m_timeoutMs / 1000;
            timeout.tv_usec = (m_timeoutMs % 1000) * 1000;

            int activity = select(m_fd + 1, &readfds, nullptr, nullptr, &timeout);
            if (activity > 0 && FD_ISSET(m_fd, &readfds)) {
                int n = read(m_fd, buffer, BUFFER_SIZE-1);
                if (n > 0 && m_serialRecHandle) {
                    m_serialRecHandle(buffer, n);  // 🔔 回调触发
                }
            } else if (activity < 0) {
                if (errno != EINTR) { // 忽略中断信号
                    std::cerr << "select失败: " << strerror(errno) << std::endl;
                    break;
                }

            }
        }
    }

    void SerialPort::startWriteThread(int32_t timeout_ms)
    {
        m_writeThread = std::thread(&SerialPort::writeLoop, this);
        m_startWriteThread= true;
        m_WtimeOutMs= timeout_ms;
    }

    void SerialPort::writeLoop()
    {

        while (!m_stopped)
        {
            std::unique_lock<std::mutex> lock(m_writeMutex);
            m_writeCv.wait_for(lock, std::chrono::milliseconds(m_WtimeOutMs),[this] 
                        { return m_stopped || !m_writeQueue.empty(); });
            if (m_stopped)
            {
                break;
            }
            if(m_writeQueue.size()>0)
            {
                std::string msg=m_writeQueue.front();
                m_writeQueue.pop();
                lock.unlock();          
                if(msg.size()>0)
                {
                    serialWrite(msg.c_str(),msg.size());
                }
            }
        }
    }

    int32_t SerialPort::serialWrite(const void *data, size_t len)
    {
        int32_t ret= -1;
        ssize_t written = write(m_fd, data, len);
        if (written < 0)
        {
            perror("write error");
            return ret;
        }
        return written;
    }

    int32_t SerialPort::serialSend(const uint8_t *data, size_t len)
    {
        int32_t ret= -1;
        if(!m_connected)
        {
            std::cerr << "Serial port is not connected" << std::endl;
            return ret;
        }
        if(data==nullptr && len == 0)
        {
            std::cerr << "Serial port data is null" << std::endl;
            return ret;
        }
        if(!m_startWriteThread)
        {
            ret= serialWrite(data,len);
        }else
        {
            if(m_writeQueue.size()>MAX_QUEUE_SIZE){
                std::cerr << "send queue is full" << std::endl;
                return ret;
            }
            std::unique_lock<std::mutex> lock(m_writeMutex);
            m_writeQueue.push(std::string((char*)data,len));
            lock.unlock();
            m_writeCv.notify_one();
            ret=0;
        }
        return ret;
    }
}


